package com.thinkit.security.config;

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Sets;
import com.thinkit.core.base.BaseContextKit;
import com.thinkit.core.constant.Constants;
import com.thinkit.core.constant.SecurityConstants;
import com.thinkit.core.handler.CustomException;
import com.thinkit.nosql.base.BaseRedisService;
import com.thinkit.security.custom.CustomJwtTokenStore;
import com.thinkit.utils.enums.UserFrom;
import com.thinkit.utils.utils.Checker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Set;

public abstract class AbsCustomJwtHandler {

    @Autowired
    BaseRedisService<String,Object> baseRedisService;

    //处理jwt 并判断是否合法
    public abstract void handlerJwtToken(Authentication authentication, JwtTokenStore tokenStore, HttpServletRequest request) throws CustomException;

    protected void handAppUserSession(Map<String, Object> details, UserFrom userFrom ){
        handPlatUserSession(details,userFrom);
    }


    protected void handPlatUserSession(Map<String, Object> details,UserFrom userFrom ){
        String jti = Checker.BeNull(details.get("jti")) ? null : details.get("jti").toString();
        String siteId = Checker.BeNull(details.get(Constants.DEFAULT_SITE)) ? null : details.get(Constants.DEFAULT_SITE).toString();
        String uid = Checker.BeNull(details.get(SecurityConstants.USER_ID)) ? null : details.get(SecurityConstants.USER_ID).toString();
        String userAccount = Checker.BeNull(details.get(SecurityConstants.USER_ACCOUNT)) ? null : details.get(SecurityConstants.USER_ACCOUNT).toString();
        String orgId = Checker.BeNull(details.get(SecurityConstants.USER_ORG_ID)) ? null : details.get(SecurityConstants.USER_ORG_ID).toString();
        Set<String> roleSings =  Checker.BeNotNull(details.get(SecurityConstants.USER_ROLE_SIGN)) ?
        CollUtil.newHashSet((List < String >)details.get(SecurityConstants.USER_ROLE_SIGN)) : Sets.newHashSet();
        ckparameters(uid,userAccount);
        ckisValidJti(jti,uid);
        checkUserLock(SecurityConstants.LOCK_ACCOUNT+userFrom.getClientId()+Constants.DOT+uid);
        BaseContextKit.setUserId(uid);
        BaseContextKit.setAccount(userAccount); //设置账号
        BaseContextKit.setUserClient(userFrom.getClientId());
        BaseContextKit.setRoleSign(roleSings);
        BaseContextKit.setSiteId(siteId);
        BaseContextKit.setOrgId(orgId);
    }

    private void ckisValidJti(String jti, String userId){
        if(Checker.BeNotBlank(jti) && Checker.BeNotBlank(userId)){
           Object valObj =  baseRedisService.get(CustomJwtTokenStore.auth+userId);
           if(Checker.BeNull(valObj)){
               throw new AccountExpiredException("您当前登录超时或者已在别处登录,您被迫下线!");
           }
            if(!valObj.toString().equals(jti)){
                throw new AccountExpiredException("您当前登录超时或者已在别处登录,您被迫下线!");
            }
        }
    }

    private void ckparameters(String... params){
        if(params.length>0){
            for(int i=0; i < params.length;i++){
                if (Checker.BeBlank(params[i])) {
                    throw new AccessDeniedException("Invalid jwt token!");
                }
            }
        }
    }


    private void checkUserLock(String key){
        boolean hasLockKey=baseRedisService.hasKey(key);
        if(hasLockKey){
            throw new AccessDeniedException("账号已被锁定,请联系管理员!");
        }
    }

    private void checkAllowMulitLogin(String userId,String tokenValue){
        if(Checker.BeNotBlank(userId)&&Checker.BeNotBlank(tokenValue)){
            Object redisTokenValue = baseRedisService.get(Constants.AllowMultiLoginKey+userId);
            if(Checker.BeNotNull(redisTokenValue)){
                boolean singleLogin=tokenValue.equals(redisTokenValue.toString());
                if(!singleLogin){
                    throw new AccessDeniedException("您的账号已经在别处登录,您被迫下线! ");
                }
            }
        }
    }

}
